﻿using AntdUI;
using FreeScheduler;
using Google.Protobuf.WellKnownTypes;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using PosClient.Helper;
using PosClient.Interfaces;
using PosClient.Model;
using PosClient.Service;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using TimeCrontab;

namespace PosClient.Job
{
    public class JobManager
    {
        Scheduler scheduler = new FreeSchedulerBuilder()
            .OnExecuting(task =>
            {
                var redis = FreeClient.Redis;
                if (redis.HExists(RedisKey.Redis_Job, task.Topic))
                {
                    var job = JsonConvert.DeserializeObject<JobEntity>(redis.HGet(RedisKey.Redis_Job, task.Topic));
                    var reflection = ToolService.ReflectionProGrom<IJob>($"Job.DownLoad.{job.JobClass}");
                    var result = reflection.Excute();
                    if (result.Success)
                    {
                        Console.WriteLine($"{result.Message} 被执行");
                    }
                    Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] {task.Topic} 被执行");
                    Logger.Default.Audit($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] {task.Topic} 被执行");
                    task.Remark("log..");
                }
                else
                {
                    Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] {task.Topic} 被执行,但缓存中没有此任务，如果确认有该任务，可以等待同步");
                }
            })
            .UseCustomInterval(task =>
            {
                //利用 cron 功能库解析 task.IntervalArgument 得到下一次执行时间
                //与当前时间相减，得到 TimeSpan，若返回 null 则任务完成
                var crontab = Crontab.Parse(task.IntervalArgument, CronStringFormat.WithSeconds);
                var nextOccurrence = crontab.GetNextOccurrence(DateTime.Now);
                TimeSpan timeDifference = nextOccurrence - DateTime.Now;
                return TimeSpan.FromTicks(timeDifference.Ticks);
            })
            .Build();

        public JobManager()
        {
        }

        public void StartAsync(JobEntity job)
        {
            scheduler.ResumeTask(job.JobCode);
        }

        public void StopAsync(JobEntity job)
        {
            scheduler.PauseTask(job.JobCode);
        }

        public void RunAllJob()
        {
            var redis = FreeClient.Redis;
            var jobs = redis.HGetAll(RedisKey.Redis_Job);
            if (jobs.Count > 0)
            {
                foreach (var jobredis in jobs)
                {
                    var job = JsonConvert.DeserializeObject<JobEntity>(jobredis.Value);
                    var reflection = ToolService.ReflectionProGrom<IJob>($"Job.DownLoad.{job.JobClass}");
                    reflection.Excute();
                }
            }
        }

        public void RunJob(JobEntity job)
        {
            var reflection = ToolService.ReflectionProGrom<IJob>($"Job.DownLoad.{job.JobClass}");
            reflection.Excute();
        }

        /// <summary>
        /// 缓存任务，全量，会先删除所有任务，然后缓存传入的任务
        /// </summary>
        /// <param name="JobList"></param>
        public void CacheJob(List<JobEntity> JobList)
        {
            if (JobList.Count > 0)
            {
                using (var conn = FreeClient.Sqlite)
                {
                    var redis = FreeClient.Redis;
                    var jobs = redis.HGetAll(RedisKey.Redis_Job);
                    if (jobs.Count > 0)
                    {
                        foreach (var jobredis in jobs)
                        {
                            var job = JsonConvert.DeserializeObject<JobEntity>(jobredis.Value);
                            conn.Delete<JobEntity>().Where(x => x.JobName == job.JobName).ExecuteAffrows();
                            scheduler.RemoveTask(job.JobCode);
                        }
                    }

                    foreach (var plu in JobList.GroupBy(y => y.JobClass).Select(x => x.FirstOrDefault()).ToDictionary(k => k.JobClass))
                    {
                        redis.HSet(RedisKey.Redis_Job, plu.Key, JsonConvert.SerializeObject(plu.Value));
                    }

                    foreach (var job in JobList)
                    {
                        conn.Insert(job).ExecuteAffrows();
                    }
                    LoadJob();
                }
            }
        }

        public void LoadJob()
        {
            if (Datafeed.GetPage(scheduler, null, null, null, null).Total == 0)
            {
                var redis = FreeClient.Redis;
                var jobs = redis.HGetAll(RedisKey.Redis_Job);
                if (jobs.Count > 0)
                {
                    foreach (var jobredis in jobs)
                    {
                        var job = JsonConvert.DeserializeObject<JobEntity>(jobredis.Value);
                        string jobCode = scheduler.AddTaskCustom(job.JobName,job.JobBody,job.JobCron);
                        job.JobCode = jobCode;
                        redis.HSet(RedisKey.Redis_Job, job.JobName, JsonConvert.SerializeObject(job));
                        using (var conn = FreeClient.Sqlite)
                        {
                            conn.Update<JobEntity>()
                                .Set(it => it.JobCode == job.JobCode)
                                .Where(x => x.JobName == job.JobName)
                                .ExecuteAffrows();
                        }
                    }
                }
                
            }
        }

    }
}
